package org.jiangy.authentication.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jiangy.Constants;
import org.jiangy.usercenter.entity.User;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextHolderStrategy;
import org.springframework.security.web.context.RequestAttributeSecurityContextRepository;
import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.security.sasl.AuthenticationException;
import java.io.IOException;

/**
 * TODO: 记录登录用户登录日志
 * TODO: 记录登录用户的额外信息，比如 IP
 * 不透明令牌认证过滤器
 * <p>创建时间: 2024/8/14 </p>
 *
 * @author <a href="mailto:jiangliu0316@outlook.com" rel="nofollow">蒋勇</a>
 */
public class OpaqueTokenAuthenticationFilter extends OncePerRequestFilter {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder.getContextHolderStrategy();
    private SecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository();
    private RedisTemplate<String, String> redisTemplate;

    public OpaqueTokenAuthenticationFilter(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String authorizationValue = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (!StringUtils.hasText(authorizationValue)) {
            filterChain.doFilter(request, response);
            return;
        }

        // TODO: 从 Redis 中恢复登录的用户信息
        authorizationValue = authorizationValue.replace("Bearer ", "");
        String userJsonValue = redisTemplate.opsForValue().get(Constants.BJQ_USER_PROFILE.formatted(authorizationValue));
        if (userJsonValue == null) {
            throw new AuthenticationException("令牌无效");
        }
        // TODO: 认证用户
//        UserDetailsProxy<?> authenticatedUser;
        User authenticatedUser;
        try {
//            authenticatedUser = UserDetailsProxy.create(userJsonValue);
            authenticatedUser = objectMapper.readValue(userJsonValue, User.class);
        } catch (JsonProcessingException e) {
            logger.error(e.getMessage(), e);
            throw new AuthenticationException("令牌无效");
        }
        // 显示处理用户类型
        UsernamePasswordAuthenticationToken authenticationResult =
                new UsernamePasswordAuthenticationToken(authenticatedUser, null, authenticatedUser.getAuthorities());

        // 认证成功后将用户信息存储到安全上下文
        SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
        context.setAuthentication(authenticationResult);
        this.securityContextHolderStrategy.setContext(context);
        this.securityContextRepository.saveContext(context, request, response);

        filterChain.doFilter(request, response);
    }


}
